package cn.isgrow.gateway.repository;

import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import cn.isgrow.gateway.entity.RouteDefinitionEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.sql.rowset.Predicate;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 *
 * @author 朱开元
 * @Date 2020-05-22 17:35
 */
@Slf4j
@Component
public class MongoRouteDefinitionRepository implements RouteDefinitionRepository {

    @Autowired private IMongoRouteDefinitionRepository mongoRouteDefinitionRepository;

    /**
     * 动态载入数据库中路由数据至缓存
     * @return
     */

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        Flux<RouteDefinitionEntity> routeEntities = mongoRouteDefinitionRepository.findAll();
        Flux<RouteDefinition> rds = routeEntities.map(this::getRouteDefinition);
        log.info("动态载入数据库中路由数据至缓存，动态配置已经生效。");
        return rds;
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return route.flatMap(rd -> {
            RouteDefinitionEntity entity = getRouteDefinitionEntity(rd);
            mongoRouteDefinitionRepository.save(entity);
            return Mono.empty();
        });
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        mongoRouteDefinitionRepository.deleteById(routeId.toString());
        log.info("动态删除数据库中路由数据");
        return Mono.empty();
    }

    /**
     * 将数据对象转化为路由定义对象
     * @param entity
     * @return
     */
    private RouteDefinition getRouteDefinition(RouteDefinitionEntity entity) {
        RouteDefinition rd = new RouteDefinition();
        rd.setId(entity.getId());
        rd.setOrder(entity.getOrder());
        rd.setUri(UriComponentsBuilder.fromHttpUrl(entity.getUri()).build().toUri());
        String filtersStr = entity.getFilters();
        if (!StringUtils.isEmpty(filtersStr)){
            List<FilterDefinition> filters = Stream.of(filtersStr.split(";")).map(f ->{
                FilterDefinition fd;
                if (f.contains("=")){
                    fd = new FilterDefinition (f);
                } else {
                    fd = JSONUtil.toBean(f, FilterDefinition.class);
                }
                return fd;
            }).collect(Collectors.toList());
            rd.setFilters(filters);
        }
        List<PredicateDefinition> predicates = Stream.of(entity.getPredicates().split(";")).map(d ->{
            PredicateDefinition pd;
            if (d.contains("=")){
                pd = new PredicateDefinition (d);
            } else {
                pd = JSONUtil.toBean(d, PredicateDefinition.class);
            }
            return pd;
        }).collect(Collectors.toList());
        rd.setPredicates(predicates);
        log.info("最新配置信息:{}", rd);
        return rd;
    }

    /**
     * 将为路由定义对象转换为数据对象
     * @param rd
     * @return entity
     */
    private RouteDefinitionEntity getRouteDefinitionEntity(RouteDefinition rd) {
        RouteDefinitionEntity entity = new RouteDefinitionEntity();
        // TODO 暂不支持动态保存路由信息至数据库
        log.error("暂不支持动态保存路由信息至数据库");
        return entity;
    }
}
